#ifndef _DAG_OPERATORS_H_
#define _DAG_OPERATORS_H_

#include "dag.h"
#include <string>
#include <iostream>
#include <memory>

namespace dag {
	
	class DAG_LOCAL OpId {
	public:
		static const std::string pass_op;
		static const std::string graph_op;
		static const std::string mult_op;
		static const std::string add_op;
		static const std::string linear_op;
		static const std::string kd_tree_op;
	};
	
	DAG_API void register_internal_inflators();
	
	class DAG_API PassOp : public FrameOperator {
	public:
		PassOp();
		virtual ~PassOp() throw();
		static std::auto_ptr<FrameOperator> inflate(std::istream& bStream);
		void operate(const Frame& input, Frame& output);
	private:
		const std::string& _frameOperatorID() const;
		void _serialize(std::ostream& binaryStream) const;
	};
	
	class DAG_API AddOp : public FrameOperator {
		AddOp();
	public:
		AddOp(const Frame& offset);
		virtual ~AddOp() throw();
		static std::auto_ptr<FrameOperator> inflate(std::istream& bStream);
		void operate(const Frame& input, Frame& output);
	private:
		const std::string& _frameOperatorID() const;
		void _serialize(std::ostream& binaryStream) const;
		
		const Frame m_Offset;
	};
	
	class DAG_API MultOp : public FrameOperator {
		MultOp();
	public:
		MultOp(const Frame& mul);
		virtual ~MultOp() throw();
		static std::auto_ptr<FrameOperator> inflate(std::istream& bStream);
		void operate(const Frame& input, Frame& output);
	private:
		const std::string& _frameOperatorID() const;
		void _serialize(std::ostream& binaryStream) const;
		const Frame m_Mult;
	};

	class DAG_API LinearOp : public FrameOperator {
		LinearOp& operator=(const LinearOp& rhs);
	public:
		LinearOp(const LinearOp& copy);
		LinearOp(const FrameSpec& inSpec, const FrameSpec& outSpec,
				 const double* const* dTrans,
				 const float* const* fTrans,
				 const int* const* iTrans,
				 const bool* const* bTrans);
		virtual ~LinearOp() throw();
		static std::auto_ptr<FrameOperator> inflate(std::istream& bStream);
		void operate(const Frame& input, Frame& output);
		
		const FrameSpec& inputSpec() const;
		const FrameSpec& outputSpec() const;
		const double* const* doubleTransform() const;
		const float* const* floatTransform() const;
		const int* const* intTransform() const;
		const bool* const* boolTransform() const;
		
	protected:
		LinearOp();
	private:
		const std::string& _frameOperatorID() const;
		void _serialize(std::ostream& binaryStream) const;
		FrameSpec m_InputSpec;
		FrameSpec m_OutputSpec;
		double** m_DTrans;
		float** m_FTrans;
		int** m_ITrans;
		bool** m_BTrans;
	};
	
	class DAG_API KdTreeOp : public FrameOperator {
		KdTreeOp();
		KdTreeOp(const KdTreeOp& copy);
		KdTreeOp& operator=(const KdTreeOp& rhs);
		
	public:
		KdTreeOp(const FrameDepot& inputs,
				 const FrameDepot& outputs);
		KdTreeOp(std::istream& bStream);
		virtual ~KdTreeOp() throw();
		static std::auto_ptr<FrameOperator> inflate(std::istream& bStream);
		void operate(const Frame& input, Frame& output);
		
	private:
		void addPair(std::auto_ptr<Frame> input,
					 std::auto_ptr<Frame> output);
		const std::string& _frameOperatorID() const;
		void _serialize(std::ostream& binaryStream) const;
		void addFrames(const Frame& input, const Frame& output);
		
		FrameSpec m_InputSpec;
		FrameSpec m_OutputSpec;
		std::set<Frame*> m_InputFrames;
		std::set<Frame*> m_OutputFrames;
		void* m_Tree;
		bool m_UseFloat32;
	};
	
	
	
}

#endif